import { DataType } from "./type";
import type { IDeserializable } from "~/models/serialize/IDeserializable";
import { Deserializer } from "~/models/serialize/Deserializer";
import { Dzer } from "~/models/serialize";
import { tAny } from ".";
import { ListType } from "./list_type";
import { InterfaceType } from "./interface_type";
import { UnionType } from "./union_type";

// 定义: 接口类型 (和类型)：
// 不是一种具体的类型，而是类型的类型。在这里定义结构和生成器

export class TypeTemplate
  extends DataType
  implements IDeserializable
{
  get name(): string {
    return this.mountType.name
  }
  get default(): any {
    return this.mountType.default
  }
  receiveType(t: DataType): boolean {
    return this.mountType.receiveType(t)
  }
  receiveValue(t: any): boolean {
    return this.mountType.receiveValue(t)
  }

  className: string = 'TypeTemplate'
  mountType: DataType = tAny

  constructor(
    public symbol: string = 'T',
  ) {
    super()
  }
}

// export const _T = (symbol?: string) => new TypeTemplate(symbol)
export const _T = new TypeTemplate('T')

/** 获取类型是否使用了模板 */
export function usedTemplate(t: DataType): boolean {
  // 本身就是
  if (t instanceof TypeTemplate) {
    return true
  }
  // list, interface, union
  if (t instanceof ListType) {
    return usedTemplate(t.itemType)
  }
  else if (t instanceof InterfaceType) {
    return t.members.some(x => usedTemplate(x.type))
  }
  else if (t instanceof UnionType) {
    return t.parallels.some(x => usedTemplate(x))
  }
  return false
}

/** 获取类型使用的模板符号 */
export function symbolsInUsing(t: DataType): string[] {
  // 本身就是
  if (t instanceof TypeTemplate) {
    return [t.symbol]
  }
  // list, interface, union
  if (t instanceof ListType) {
    return symbolsInUsing(t.itemType)
  }
  else if (t instanceof InterfaceType) {
    return lodash.flatten(t.members.map(x => symbolsInUsing(x.type)))
  }
  else if (t instanceof UnionType) {
    return lodash.flatten(t.parallels.map(x => symbolsInUsing(x)))
  }
  return []
}

interface UpdateInfo {
  symbol: string
  type: DataType
}

/**
 * 对比更新的类型来更新模板
 * 例如模板类型tUsingT是 List<T>, 更新类型是List<string>.
 * 最终根据对比，T = string
 * 
 * @returns 返回实际更新的内部类型
 */
export function updateTemplateByComparison(tUsingT: DataType, tUpdate: DataType): UpdateInfo {
  // 本身就是
  if (tUsingT instanceof TypeTemplate) {
    tUsingT.mountType = tUpdate
    return {
      type: tUpdate,
      symbol: tUsingT.symbol
    }
  }
  // list, interface, union
  if (
    tUsingT instanceof ListType
    && tUpdate instanceof ListType
    && tUsingT.itemType instanceof TypeTemplate
  ) {
    const _t = tUpdate.itemType
    tUsingT.itemType.mountType = _t
    return {
      type: _t,
      symbol: tUsingT.itemType.symbol
    }
  }
  else if (
    tUsingT instanceof InterfaceType
    && tUpdate instanceof InterfaceType
    && tUsingT.members.some(x => x.type instanceof TypeTemplate)
  ) {
    let innerType: DataType | null = null
    let innerSymbol : string | null = null
    // const _t = tUpdate.members.find(x => x.type instanceof TypeTemplate)
    tUsingT.members.forEach(member => {
      if (member.type instanceof TypeTemplate) {
        const findType = tUpdate.members.find(x => x.name === member.name)
        if (!findType) {
          console.error('tUsingT', tUsingT);
          console.error('tUpdate', tUpdate);
          throw "接口类型模板更新失败"
        }
        innerType = findType.type
        innerSymbol = member.type.symbol
        member.type.mountType = findType.type
      }
    })
    if (!innerType || !innerSymbol) {
      console.error('tUsingT', tUsingT);
      console.error('tUpdate', tUpdate);
      throw "接口类型模板更新失败"
    }
    return {
      type: innerType,
      symbol: innerSymbol,
    }
  }
  else if (
    tUsingT instanceof UnionType
    && tUpdate instanceof UnionType
    && tUsingT.parallels.some(x => x instanceof TypeTemplate)
  ) {
    let innerType: DataType | null = null
    let innerSymbol : string | null = null

    tUsingT.parallels.forEach(para => {
      if (para instanceof TypeTemplate) {
        const findType = tUpdate.parallels.find(x => x.name === para.name)
        if (!findType) {
          console.error('tUsingT', tUsingT);
          console.error('tUpdate', tUpdate);
          throw "UnionType模板更新失败"
        }
        innerType = findType
        para.mountType = findType
      }
    })
    if (!innerType || !innerSymbol) {
      console.error('tUsingT', tUsingT);
      console.error('tUpdate', tUpdate);
      throw "UnionType模板更新失败"
    }
    return {
      type: innerType,
      symbol: innerSymbol,
    }
  }
  console.error('tUsingT', tUsingT);
  console.error('tUpdate', tUpdate);
  throw "类型模板更新失败"
}


/**
 * 直接更新模板
 * 例如模板类型tUsingT是 List<T>, 更新类型是string.
 * 最终T = string
 */
export function updateTemplateDirect(tUsingT: DataType, tInner: DataType) {
  // 本身就是
  if (tUsingT instanceof TypeTemplate) {
    tUsingT.mountType = tInner
    return
  }
  // list, interface, union
  if (
    tUsingT instanceof ListType
    && tUsingT.itemType instanceof TypeTemplate
  ) {
    tUsingT.itemType.mountType = tInner
    return
  }
  else if (
    tUsingT instanceof InterfaceType
    && tUsingT.members.some(x => x.type instanceof TypeTemplate)
  ) {
    // const _t = tUpdate.members.find(x => x.type instanceof TypeTemplate)
    tUsingT.members.forEach(member => {
      if (member.type instanceof TypeTemplate) {
        member.type.mountType = tInner
      }
    })
    return
  }
  else if (
    tUsingT instanceof UnionType
    && tUsingT.parallels.some(x => x instanceof TypeTemplate)
  ) {
    tUsingT.parallels.forEach(para => {
      if (para instanceof TypeTemplate) {
        para.mountType = tInner
      }
    })
    return
  }
  console.error('tUsingT', tUsingT);
  console.error('tUpdate', tInner);
  throw "类型模板更新失败"
}